﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

using CtrLayer;
using ModelLayer;

namespace GUILayer
{
    public partial class GUIShowPlanning : Form
    {
        CinemaController ctrCinema = new CinemaController();
        MovieController ctrMovie = new MovieController();
        RoomController ctrRoom = new RoomController();
        ShowController ctrShow = new ShowController();

        List<Room> cinemaRooms = new List<Room>();
        List<Movie> dailyMovies = new List<Movie>();
        List<Show> dailyShows = new List<Show>();

        //Global Settings.
        private int hourStart = 14;
        private int hourEnd = 2;
        private int minShowPause = 20;
        Color colorFadeFull = Color.NavajoWhite;
        Color colorFadePartial = Color.AntiqueWhite;

        //Initialize form.
        public GUIShowPlanning()
        {
            InitializeComponent();

            //Disable inputs.
            clndrPlanningDate.Enabled = false;
            clndrPlanningDate.BackColor = Color.LightGray;
            grdvwPlanningShows.Enabled = false;
            nmrcPlanningTimeMinute.Enabled = false;
            cmbPlanningMovie.Enabled = false;
            txtPlanningPrice.Enabled = false;
            btnPlanningAddShow.Enabled = false;
            btnPlanningRemoveShow.Enabled = false;

            //Reset and populate cinema combobox.
            cmbPlanningCinema.SelectedIndex = -1;
            cmbPlanningCinema.Items.Clear();
            List<Cinema> cinemas = ctrCinema.GetCinemas();
            if (cinemas.Count > 0)
            {
                cmbPlanningCinema.Items.AddRange(cinemas.ToArray());
            }
        }

        //Resets and recreates the gridview, and disables all child inputs.
        private void createSchedule()
        {
            //Reseting gridview.
            grdvwPlanningShows.ColumnCount = 0;
            grdvwPlanningShows.RowCount = 0;

            //Creating room columns.
            int roomCount = cinemaRooms.Count;
            grdvwPlanningShows.ColumnCount = roomCount;
            for (int i = 0; i < roomCount; i++)
            {
                grdvwPlanningShows.Columns[i].Name = "Sal " + cinemaRooms[i].Name;
            }

            //Calculating row span.
            int hourSpan = hours2Span(hourStart, hourEnd) + 1;

            //Creating hour rows.
            grdvwPlanningShows.RowCount = hourSpan;
            for (int i = 0; i < hourSpan; i++)
            {
                int hour = row2Hour(i);
                string hourString = time2String(hour) + ":00";
                grdvwPlanningShows.Rows[i].HeaderCell.Value = hourString;
            }

            //Clear gridview selection.
            grdvwPlanningShows.ClearSelection();
        }

        //Populate gridview with existing shows.
        private void populateSchedule(List<Show> shows, DateTime dateTimeStart, DateTime dateTimeEnd)
        {
            //Add each show to gridview.
            foreach (Show show in shows)
            {
                //Verify show date and cinema.
                if ((show.DateTime >= dateTimeStart) && (show.DateTime < dateTimeEnd) && (show.Room.Cinema.Equals((Cinema)cmbPlanningCinema.SelectedItem)))
                {
                    //Find column id.
                    int showCol = cinemaRooms.IndexOf(show.Room);

                    //Calculate row id.
                    int showRow = show.DateTime.Hour;
                    if (show.DateTime.AddDays(-1).Date == clndrPlanningDate.SelectionStart.Date)
                    {
                        showRow += 24;
                    }
                    showRow -= hourStart;

                    //Write selected timestamp and movie title to selected hour cell.
                    grdvwPlanningShows.Rows[showRow].Cells[showCol].Value = show;

                    //Fade filled-out hour cells.
                    fadeCells(showRow, showCol, show.DateTime.Minute, show.Movie.PlayLength);
                }
            }
        }

        //Gets the Show of the selected faded cell.
        private Show getSelectedShow(int selRow, int selCol)
        {
            Show selShow = null;
            while ((selShow == null) && (selRow >= 0))
            {
                selShow = (Show)grdvwPlanningShows.Rows[selRow].Cells[selCol].Value;
                selRow--;
            }
            return selShow;
        }

        //Fade/Unfade filled-out hour cells.
        private void fadeCells(int selRow, int selCol, int startMin, int playLength)
        {
            //Calculating end time.
            int countMin = startMin + playLength + minShowPause;

            //Enter loop to fade out each filled hour cell.
            while ((countMin >= 60) && (selRow < grdvwPlanningShows.Rows.Count))
            {
                //Check starting cell for start offset.
                if (startMin > 0)
                {
                    startMin = 0;

                    //Set cell color for partial fade.
                    grdvwPlanningShows.Rows[selRow].Cells[selCol].Style.BackColor = colorFadePartial;
                }
                else
                {
                    //Set cell color for full fade.
                    grdvwPlanningShows.Rows[selRow].Cells[selCol].Style.BackColor = colorFadeFull;
                }

                //Increase row id.
                selRow++;

                //Decrease countMin and repeat loop.
                countMin = countMin - 60;
            }

            //Check next cell for partial fill.
            if ((countMin > 0) && (selRow < grdvwPlanningShows.Rows.Count))
            {
                //Set cell color for partial fade.
                grdvwPlanningShows.Rows[selRow].Cells[selCol].Style.BackColor = colorFadePartial;
            }
        }

        //Checks if new show overlaps existing shows.
        private bool checkShowCollision(Room selRoom, DateTime newShowStart, DateTime newShowEnd)
        {
            Boolean collisionState = false;
            foreach (Show show in dailyShows)
            {
                if (show.Room.Equals(selRoom))
                {
                    //Calculate show start and end.
                    DateTime showStart = show.DateTime;
                    DateTime showEnd = show.DateTime.AddMinutes(show.Movie.PlayLength + minShowPause);

                    //Check if new show is within existing show.
                    if (((newShowStart >= showStart) && (newShowStart <= showEnd)) || ((newShowEnd >= showStart) && (newShowEnd <= showEnd)))
                    {
                        collisionState = true;
                    }

                    //Check if existing show is within new show.
                    if (((showStart >= newShowStart) && (showStart <= newShowEnd)) || ((showEnd >= newShowStart) && (showEnd <= newShowEnd)))
                    {
                        collisionState = true;
                    }
                }
            }
            return collisionState;
        }

        //Calculates hour span from given start and end hours.
        private int hours2Span(int hourStart, int hourEnd)
        {
            int hourSpan = 0;
            if (hourStart > hourEnd)
            {
                hourSpan = (hourEnd + 24) - hourStart;
            }
            else
            {
                hourSpan = hourEnd - hourStart;
            }
            return hourSpan;
        }
        
        //Calculates and returns hour from given row id.
        private int row2Hour(int row)
        {
            int hour = row + hourStart;
            if (hour >= 24)
            {
                hour -= 24;
            }
            return hour;
        }

        //Converts time integers to zerofilled timestamp strings.
        private string time2String(int time)
        {
            string timeString = time.ToString();
            if (time < 10)
            {
                timeString = "0" + timeString;
            }
            return timeString;
        }

        private void cmbPlanningCinema_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Disabling inputs.
            grdvwPlanningShows.Enabled = false;
            nmrcPlanningTimeMinute.Enabled = false;
            cmbPlanningMovie.Enabled = false;
            txtPlanningPrice.Enabled = false;
            btnPlanningAddShow.Enabled = false;
            btnPlanningRemoveShow.Enabled = false;

            //Reseting gridview.
            grdvwPlanningShows.ColumnCount = 0;
            grdvwPlanningShows.RowCount = 0;

            //Enable child inputs.
            clndrPlanningDate.Enabled = true;
            clndrPlanningDate.BackColor = Color.White;

            //Get list of cinema rooms.
            cinemaRooms = ctrRoom.GetRooms((Cinema)cmbPlanningCinema.SelectedItem);
        }

        private void clndrPlanningDate_DateSelected(object sender, DateRangeEventArgs e)
        {
            //Disabling inputs.
            nmrcPlanningTimeMinute.Enabled = false;
            cmbPlanningMovie.Enabled = false;
            txtPlanningPrice.Enabled = false;
            btnPlanningAddShow.Enabled = false;
            btnPlanningRemoveShow.Enabled = false;

            //Enable child input.
            grdvwPlanningShows.Enabled = true;

            //Calculate schedule start and end.
            DateTime dateTime = clndrPlanningDate.SelectionStart;
            DateTime dateTimeStart = clndrPlanningDate.SelectionStart.AddHours(hourStart);
            DateTime dateTimeEnd = clndrPlanningDate.SelectionEnd.AddHours((double)(hourStart + hours2Span(hourStart, hourEnd) + 1));

            //Reset and populate movie combobox.
            cmbPlanningMovie.SelectedIndex = -1;
            cmbPlanningMovie.Items.Clear();

            //Get list of movies from selected date, and populate movie combobox.
            dailyMovies = ctrMovie.GetMovies(dateTime);
            if (dailyMovies.Count > 0)
            {
                cmbPlanningMovie.Items.AddRange(dailyMovies.ToArray());
            }

            //Recreate Gridview.
            createSchedule();

            //Get list of shows from selected date, and populate schedule gridview.
            dailyShows = ctrShow.GetShows(dateTimeStart, dateTimeEnd);
            if (dailyShows.Count > 0)
            {
                populateSchedule(dailyShows, dateTimeStart, dateTimeEnd);
            }
        }

        private void grdvwPlanningShows_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            //Get selected cell, row, column and hour.
            DataGridViewCell selCell = grdvwPlanningShows.SelectedCells[0];
            int selRow = selCell.RowIndex;
            int selCol = selCell.ColumnIndex;
            int hour = row2Hour(selRow);

            //Check is cell is fully used or cell is first cell of a show.
            if (selCell.Style.BackColor.Equals(colorFadeFull) || (selCell.Style.BackColor.Equals(colorFadePartial) && (selCell.Value != null)))
            {
                //Get selected show.
                Show selShow = getSelectedShow(selRow, selCol);

                //Disable child inputs.
                nmrcPlanningTimeMinute.Enabled = false;
                nmrcPlanningTimeMinute.Minimum = 0;
                nmrcPlanningTimeMinute.Value = selShow.DateTime.Minute;
                cmbPlanningMovie.Enabled = false;
                cmbPlanningMovie.SelectedIndex = dailyMovies.IndexOf(selShow.Movie);
                txtPlanningPrice.Enabled = false;
                txtPlanningPrice.Text = selShow.ShowPrice.ToString();
                btnPlanningRemoveShow.Enabled = true;

                //Write selected hour to input form.
                txtPlanningTimeHour.Text = time2String(selShow.DateTime.Hour);
            }

            //Check if cell is end cell of a show.
            else if (selCell.Style.BackColor.Equals(colorFadePartial))
            {
                //Get selected show.
                Show selShow = getSelectedShow(selRow, selCol);

                //Calculate show end.
                DateTime showEnd = selShow.DateTime.AddMinutes(selShow.Movie.PlayLength + minShowPause);

                //Enable child inputs.
                nmrcPlanningTimeMinute.Enabled = true;
                nmrcPlanningTimeMinute.Minimum = (showEnd.Minute + 1);
                nmrcPlanningTimeMinute.Value = (showEnd.Minute + 1);
                cmbPlanningMovie.Enabled = true;
                cmbPlanningMovie.SelectedIndex = -1;
                txtPlanningPrice.Enabled = true;
                txtPlanningPrice.Text = "";
                btnPlanningRemoveShow.Enabled = false;

                //Write selected hour to input form.
                txtPlanningTimeHour.Text = time2String(hour);
            }

            //When cell is clear enable add show form
            else
            {
                //Enable child inputs.
                nmrcPlanningTimeMinute.Enabled = true;
                nmrcPlanningTimeMinute.Minimum = 0;
                nmrcPlanningTimeMinute.Value = 0;
                cmbPlanningMovie.Enabled = true;
                cmbPlanningMovie.SelectedIndex = -1;
                txtPlanningPrice.Enabled = true;
                txtPlanningPrice.Text = "";
                btnPlanningRemoveShow.Enabled = false;

                //Write selected hour to input form.
                txtPlanningTimeHour.Text = time2String(hour);
            }

            //Disabling inputs.
            btnPlanningAddShow.Enabled = false;

            //Write selected room to input form.
            lblPlanningRoom.Text = "Sal " + cinemaRooms[selCol].Name;
        }

        private void cmbPlanningMovie_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Enable child inputs.
            btnPlanningAddShow.Enabled = true;
        }

        private void btnPlanningRemoveShow_Click(object sender, EventArgs e)
        {
            //Get selected row, column and show.
            int selRow = grdvwPlanningShows.SelectedCells[0].RowIndex;
            int selCol = grdvwPlanningShows.SelectedCells[0].ColumnIndex;
            Show selShow = getSelectedShow(selRow, selCol);

            //Calculate schedule start and end.
            DateTime selDateTime = clndrPlanningDate.SelectionStart;
            DateTime scheduleDateTimeStart = selDateTime.AddHours(hourStart);
            DateTime scheduleDateTimeEnd = selDateTime.AddHours(hourStart + hours2Span(hourStart, hourEnd) + 1);

            if (MessageBox.Show("Vil du fjerne \"" + selShow.ToString() + "\" i Sal " + selShow.Room.Name + "?", "Fjern Show?", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                //Remove show from database.
                if (ctrShow.DeleteShow(selShow.Id) > -1)
                {
                    //Recreate Gridview.
                    createSchedule();

                    //Get list of shows from selected date, and repopulate schedule gridview.
                    dailyShows = ctrShow.GetShows(scheduleDateTimeStart, scheduleDateTimeEnd);
                    if (dailyShows.Count > 0)
                    {
                        populateSchedule(dailyShows, scheduleDateTimeStart, scheduleDateTimeEnd);

                        //Disabling inputs.
                        nmrcPlanningTimeMinute.Enabled = false;
                        nmrcPlanningTimeMinute.Minimum = 0;
                        nmrcPlanningTimeMinute.Value = 0;
                        cmbPlanningMovie.Enabled = false;
                        cmbPlanningMovie.SelectedIndex = -1;
                        txtPlanningPrice.Enabled = false;
                        txtPlanningPrice.Text = "";
                        btnPlanningAddShow.Enabled = false;
                        btnPlanningRemoveShow.Enabled = false;
                    }
                }
                else
                {
                    MessageBox.Show("Forestillingen kunne ikke fjernes.");
                }
            }
        }

        private void btnPlanningAddShow_Click(object sender, EventArgs e)
        {
            decimal selPrice;
            if (Decimal.TryParse(txtPlanningPrice.Text, out selPrice))
            {
                //Get selected row and column.
                int selRow = grdvwPlanningShows.SelectedCells[0].RowIndex;
                int selCol = grdvwPlanningShows.SelectedCells[0].ColumnIndex;

                //Get selected Movie, Room and price.
                Movie selMovie = (Movie)cmbPlanningMovie.SelectedItem;
                Room selRoom = cinemaRooms[selCol];

                //Calculate schedule start and end.
                DateTime selDateTime = clndrPlanningDate.SelectionStart;
                DateTime scheduleDateTimeStart = selDateTime.AddHours(hourStart);
                DateTime scheduleDateTimeEnd = selDateTime.AddHours(hourStart + hours2Span(hourStart, hourEnd) + 1);

                //Calculate show start and end.
                DateTime showDateTimeStart = new DateTime(selDateTime.Year, selDateTime.Month, selDateTime.Day, hourStart, 0, 0);
                showDateTimeStart = showDateTimeStart.AddHours(selRow);
                showDateTimeStart = showDateTimeStart.AddMinutes((int)nmrcPlanningTimeMinute.Value);
                DateTime showDateTimeEnd = showDateTimeStart.AddMinutes(selMovie.PlayLength + minShowPause);

                //Create new show and calculate start and end time.
                Show newShow = new Show(selMovie, selRoom, showDateTimeStart, selPrice);

                if (checkShowCollision(selRoom, showDateTimeStart, showDateTimeEnd))
                {
                    MessageBox.Show("Forestillingen overlapper en anden.");
                }

                //Add show to database.
                else if (ctrShow.AddShow(newShow) > -1)
                {
                    //Recreate Gridview.
                    createSchedule();

                    //Get list of shows from selected date, and repopulate schedule gridview.
                    dailyShows = ctrShow.GetShows(scheduleDateTimeStart, scheduleDateTimeEnd);
                    if (dailyShows.Count > 0)
                    {
                        populateSchedule(dailyShows, scheduleDateTimeStart, scheduleDateTimeEnd);

                        //Disabling inputs.
                        nmrcPlanningTimeMinute.Enabled = false;
                        nmrcPlanningTimeMinute.Minimum = 0;
                        nmrcPlanningTimeMinute.Value = 0;
                        cmbPlanningMovie.Enabled = false;
                        cmbPlanningMovie.SelectedIndex = -1;
                        txtPlanningPrice.Enabled = false;
                        txtPlanningPrice.Text = "";
                        btnPlanningAddShow.Enabled = false;
                        btnPlanningRemoveShow.Enabled = false;
                    }
                }
                else
                {
                    MessageBox.Show("Forestillingen kunne ikke oprettes.");
                }
            }
            else
            {
                txtPlanningPrice.Text = "";
                MessageBox.Show("Ugyldig pris.");
            }
        }

        private void btnPlanningBack_Click(object sender, EventArgs e)
        {
            //Go back to main form.
            Form newForm = new GUIStart();
            this.Hide();
            newForm.ShowDialog();
            this.Close();
        }
    }
}
